package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.framework.web.RemoteResult;
import com.binary.jdbc.Page;
import com.uinnova.product.cj.feign.dto.PlanArtifactDTO;
import com.uinnova.product.cj.feign.dto.PlanDesignInstanceDTO;
import com.uinnova.product.cj.feign.dto.PlanDesignShareRecordDTO;
import com.uinnova.product.cj.feign.dto.PlanVersionDTO;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.*;
import com.uinnova.product.eam.model.EamNoticeTransVo;
import com.uinnova.product.eam.model.EamNoticeVo;
import com.uinnova.product.eam.model.asset.AnnotationMsgDTO;
import com.uinnova.product.eam.model.asset.QuestionMsgDTO;
import com.uinnova.product.eam.model.asset.ShareMsgDTO;
import com.uinnova.product.eam.model.cj.domain.ChapterInstance;
import com.uinnova.product.eam.model.cj.domain.PlanArtifact;
import com.uinnova.product.eam.model.cj.domain.PlanDesignInstance;
import com.uinnova.product.eam.model.constants.NoticeConstant;
import com.uinnova.product.eam.model.enums.CategoryTypeEnum;
import com.uinnova.product.eam.model.vo.*;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.cj.service.PlanArtifactService;
import com.uinnova.product.eam.service.cj.service.PlanChapterInstanceService;
import com.uinnova.product.eam.service.cj.service.PlanDesignInstanceService;
import com.uinnova.product.eam.service.es.EamNoticeDao;
import com.uinnova.product.eam.service.todo.GTJobSvc;
import com.uinnova.product.eam.service.todo.dto.GTSendPendingJobInfo;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.diagram.DiagramShareRecord;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import com.uino.bean.permission.query.CSysUser;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
@EnableAsync
public class EamNoticeServiceImpl implements IEamNoticeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EamNoticeServiceImpl.class);

    private static final Long DEFAULT_DOMAIN_ID = 1L;

    @Autowired
    private EamNoticeDao eamNoticeDao;
    @Autowired
    private ESDiagramApiClient esDiagramSvc;
    @Autowired
    private IUserApiSvc userApiSvc;
    @Autowired
    private WorkbenchChargeDoneSvc workbenchChargeDoneSvc;
    @Autowired
    private ShareDiagramSvc shareDiagramSvc;
    @Resource
    private PlanDesignInstanceService planDesignInstanceService;
    @Resource
    private PlanArtifactService planArtifactService;
    @Resource
    private PlanChapterInstanceService planChapterInstanceService;
    @Autowired
    private DiagramApproveRltSvc diagramApproveRltSvc;
    @Autowired
    private EamCategorySvc categorySvc;
    @Autowired
    private IBmMultiModelHierarchySvc modelHierarchySvc;
    @Value("${gt.data.imitate:false}")
    private Boolean gtDataImitate;
    @Autowired
    private GTJobSvc gtJobSvc;
    @Autowired
    private ICISwitchSvc ciSwitchSvc;
    @Value("${http.resource.space}")
    private String httpPath;

    @Override
    public void diagramUpdateMsgSave(List<String> dEnergies) {
        RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
        try {
            this.doDiagramUpdateMsgASyncSave(dEnergies);
        } catch (Exception e) {
            LOGGER.error("视图更新推送消息异常:{}", e.getMessage());
        }
    }

    @Async
    public void doDiagramUpdateMsgASyncSaveToWorkBench(List<String> dEnergies) {
        if (CollectionUtils.isEmpty(dEnergies)) {
            LOGGER.info("消息：视图id为空，结束");
            return;
        }
        List<ESDiagram> diagrams = esDiagramSvc.queryDBDiagramInfoByIds(dEnergies.toArray(new String[dEnergies.size()]));
        String msg;
        if (CollectionUtils.isEmpty(diagrams)) {
            msg = JSON.toJSONString(dEnergies);
            LOGGER.info("消息：未查询到视图信息，结束。params[{}]", msg);
            return;
        }
        msg = JSON.toJSONString(diagrams);
        LOGGER.info("消息：视图信息：{}", msg);
        //发布过的视图
        diagrams = diagrams.stream().filter(d -> d.getReleaseVersion() != null && d.getReleaseVersion() != 1).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(diagrams)) {
            LOGGER.info("消息：无满足条件视图，结束");
            return;
        }
        /**这里需要拿设计库视图id排除一下方案关联设计库视图的情况--不发消息。。
         但又引申出另外一个问题：方案关联设计库视图，方案发布视图同步发布后，其他人资产库检出这个方案到本地再次发布，关联的视图同步发布时，这会还要不要发消息
         按目前的逻辑，只要这个方案从一开始关联的视图是设计库视图，不管方案被检出多少次，被检出的方案发布时都不会因为同步发布视图而去给当前方案发消息。
         先这样吧。。方案关联视图版本更新场景比较多，等抽空好好捋捋。。。
         **/
        List<String> privateDiagramIds = diagrams.stream().map(ESDiagram::getDEnergy).distinct().collect(Collectors.toList());
        List<String> releaseDiagramIds = diagrams.stream().map(ESDiagram::getReleaseDiagramId).distinct().collect(Collectors.toList());
        //获取视图被关联的方案
        List<PlanArtifact> planArtifacts = planArtifactService.findPlanReleaseDiagramList(privateDiagramIds, releaseDiagramIds);
        List<PlanArtifactDTO> planArtifactDTOS = new ArrayList<>();
        for (PlanArtifact planArtifact : planArtifacts) {
            PlanArtifactDTO dto = new PlanArtifactDTO();
            BeanUtils.copyProperties(planArtifact, dto);
            planArtifactDTOS.add(dto);
        }
        if (CollectionUtils.isEmpty(planArtifactDTOS)) {
            msg = JSON.toJSONString(dEnergies);
            LOGGER.info("消息：当前视图无方案关联，结束。params[{}]", msg);
            return;
        }
        Map<Long, List<PlanArtifactDTO>> planDiagramMap = planArtifactDTOS.stream().collect(Collectors.groupingBy(PlanArtifactDTO::getPlanId));
        //获取方案信息
        List<Long> planIds = planArtifactDTOS.stream().map(PlanArtifactDTO::getPlanId).distinct().collect(Collectors.toList());
        msg = JSON.toJSONString(planIds);
        LOGGER.info("消息：被关联的方案ids：{}", msg);

        List<PlanDesignInstance> planDesignInstances = planDesignInstanceService.getByIds(planIds);
        List<PlanDesignInstanceDTO> planDesignInstanceDTOS = new ArrayList<>();
        for (PlanDesignInstance instance : planDesignInstances) {
            PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(instance, planDesignInstanceDTO);
            planDesignInstanceDTOS.add(planDesignInstanceDTO);
        }
        //推送消息方案列表
        List<PlanDesignInstanceDTO> sendMsgPlanList = this.getFilterPlansWhenDiagramUpdate(planDesignInstanceDTOS);
        if (CollectionUtils.isEmpty(sendMsgPlanList)) {
            LOGGER.info("消息：未查询到符合的方案信息，结束");
            return;
        }
        List<WorkbenchChargeDone> workbenchChargeDoneList = new ArrayList<>();
        WorkbenchChargeDone chargeDone;
        for (PlanDesignInstanceDTO instance : sendMsgPlanList) {
            chargeDone = new WorkbenchChargeDone();
            chargeDone.setType(2);
            chargeDone.setAction(1);
            chargeDone.setBusinessId(ESUtil.getUUID() + "");
            chargeDone.setUserId(instance.getCreatorCode());
            chargeDone.setTaskCreateTime(new Date());

            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> params = new ConcurrentHashMap<>();
            //私有仓库
            if (instance.getAssetsType() == 1) {
                chargeDone.setContent(String.format(NoticeConstant.PLAN_DIAGRAM_UPDATE_PRIVATE_TEMPLATE, instance.getName()));
                params.put(NoticeConstant.PLAN_ID, instance.getId().toString());
                params.put(NoticeConstant.SOURCE_TYPE, 0);
            }
            //资产库
            if (instance.getAssetsType() == 2) {
                chargeDone.setContent(String.format(NoticeConstant.PLAN_DIAGRAM_UPDATE_DESIGN_TEMPLATE, instance.getName()));
                params.put(NoticeConstant.PLAN_ID, instance.getBusinessKey());
                params.put(NoticeConstant.SOURCE_TYPE, 1);
            }
            keywords.add(new EamNoticeKeyword(instance.getName(), params));
            chargeDone.setKeywords(keywords);
            chargeDone.setPlanId(instance.getAssetsType() == 1 ? instance.getId().toString() : instance.getBusinessKey());
            chargeDone.setDiagramIds(planDiagramMap.getOrDefault(instance.getId(), new ArrayList<>())
                    .stream().map(PlanArtifactDTO::getReleaseDiagramId).distinct().collect(Collectors.toList()));
            chargeDone.setSourceType(Integer.valueOf(params.get(NoticeConstant.SOURCE_TYPE).toString()));
            workbenchChargeDoneList.add(chargeDone);
        }
        msg = JSON.toJSONString(workbenchChargeDoneList);
        LOGGER.info("推送方案关联视图更新消息至代办：{}", msg);
        workbenchChargeDoneSvc.saveOrUpdate(workbenchChargeDoneList);
    }

    @Async
    public void doDiagramUpdateMsgASyncSave(List<String> dEnergies) {
        if (CollectionUtils.isEmpty(dEnergies)) {
            LOGGER.info("消息：视图id为空，结束");
            return;
        }
        List<ESDiagram> diagrams = esDiagramSvc.queryDBDiagramInfoByIds(dEnergies.toArray(new String[dEnergies.size()]));
        String msg;
        if (CollectionUtils.isEmpty(diagrams)) {
            msg = JSON.toJSONString(dEnergies);
            LOGGER.info("消息：未查询到视图信息，结束。params[{}]", msg);
            return;
        }
        msg = JSON.toJSONString(diagrams);
        LOGGER.info("消息：视图信息：{}", msg);
        //发布过的视图
        diagrams = diagrams.stream().filter(d -> d.getReleaseVersion() != null && d.getReleaseVersion() != 1).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(diagrams)) {
            LOGGER.info("消息：无满足条件视图，结束");
            return;
        }
        /**这里需要拿设计库视图id排除一下方案关联设计库视图的情况--不发消息。。
         但又引申出另外一个问题：方案关联设计库视图，方案发布视图同步发布后，其他人资产库检出这个方案到本地再次发布，关联的视图同步发布时，这会还要不要发消息
         按目前的逻辑，只要这个方案从一开始关联的视图是设计库视图，不管方案被检出多少次，被检出的方案发布时都不会因为同步发布视图而去给当前方案发消息。
         先这样吧。。方案关联视图版本更新场景比较多，等抽空好好捋捋。。。
         **/
        List<String> privateDiagramIds = diagrams.stream().map(ESDiagram::getDEnergy).distinct().collect(Collectors.toList());
        List<String> releaseDiagramIds = diagrams.stream().map(ESDiagram::getReleaseDiagramId).distinct().collect(Collectors.toList());
        //获取视图被关联的方案
        List<PlanArtifact> planArtifacts = planArtifactService.findPlanReleaseDiagramList(privateDiagramIds, releaseDiagramIds);
        List<PlanArtifactDTO> planArtifactDTOS = new ArrayList<>();
        for (PlanArtifact planArtifact : planArtifacts) {
            PlanArtifactDTO dto = new PlanArtifactDTO();
            BeanUtils.copyProperties(planArtifact, dto);
            planArtifactDTOS.add(dto);
        }
        if (CollectionUtils.isEmpty(planArtifactDTOS)) {
            msg = JSON.toJSONString(dEnergies);
            LOGGER.info("消息：当前视图无方案关联，结束。params[{}]", msg);
            return;
        }
        Map<Long, List<PlanArtifactDTO>> planDiagramMap = planArtifactDTOS.stream().collect(Collectors.groupingBy(PlanArtifactDTO::getPlanId));
        //获取方案信息
        List<Long> planIds = planArtifactDTOS.stream().map(PlanArtifactDTO::getPlanId).distinct().collect(Collectors.toList());
        msg = JSON.toJSONString(planIds);
        LOGGER.info("消息：被关联的方案ids：{}", msg);

        List<PlanDesignInstance> planDesignInstances = planDesignInstanceService.getByIds(planIds);
        List<PlanDesignInstanceDTO> planDesignInstanceDTOS = new ArrayList<>();
        for (PlanDesignInstance instance : planDesignInstances) {
            PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(instance, planDesignInstanceDTO);
            planDesignInstanceDTOS.add(planDesignInstanceDTO);
        }
        //推送消息方案列表
        List<PlanDesignInstanceDTO> sendMsgPlanList = this.getFilterPlansWhenDiagramUpdate(planDesignInstanceDTOS);
        if (CollectionUtils.isEmpty(sendMsgPlanList)) {
            LOGGER.info("消息：未查询到符合的方案信息，结束");
            return;
        }
        List<EamNotice> eamNotices = new ArrayList<>();
        EamNotice notice;
        for (PlanDesignInstanceDTO instance : sendMsgPlanList) {
            notice = new EamNotice();
            notice.setId(ESUtil.getUUID());
            notice.setDomainId(DEFAULT_DOMAIN_ID);
            notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
            notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
            notice.setRead(0);
            notice.setUserName(instance.getCreatorCode());
            notice.setTag(NoticeConstant.TAG_PLAN);
            notice.setIsDeleted(0);
            notice.setMsgType(NoticeConstant.MSG_TYPE_PLAN_DIAGRAM_UPDATE);
            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> params = new ConcurrentHashMap<>();
            //私有仓库
            if (instance.getAssetsType() == 1) {
                notice.setContent(String.format(NoticeConstant.PLAN_DIAGRAM_UPDATE_PRIVATE_TEMPLATE, instance.getName()));
                params.put(NoticeConstant.PLAN_ID, instance.getId().toString());
                params.put(NoticeConstant.SOURCE_TYPE, 0);
            }
            //资产库
            if (instance.getAssetsType() == 2) {
                notice.setContent(String.format(NoticeConstant.PLAN_DIAGRAM_UPDATE_DESIGN_TEMPLATE, instance.getName()));
                params.put(NoticeConstant.PLAN_ID, instance.getBusinessKey());
                params.put(NoticeConstant.SOURCE_TYPE, 1);
            }
            notice.setCustomer(params.get(NoticeConstant.SOURCE_TYPE).toString());
            notice.setCustomer1(params.get(NoticeConstant.PLAN_ID).toString());
            keywords.add(new EamNoticeKeyword(instance.getName(), params));
            notice.setKeywords(keywords);
            eamNotices.add(notice);
        }
        eamNoticeDao.saveOrUpdateBatch(eamNotices);
    }

    /**
     * 视图更新，推送方案过滤
     * @param planDesignInstanceDTOS
     * @return
     */
    private List<PlanDesignInstanceDTO> getFilterPlansWhenDiagramUpdate(List<PlanDesignInstanceDTO> planDesignInstanceDTOS) {
        if (CollectionUtils.isEmpty(planDesignInstanceDTOS)) {
            return new ArrayList<>();
        }
        /**
         * 定义：
         *   A_PRIVATE_1：A用户设计库方案
         *   A_DESIGN_1：A用户发布A_PRIVATE_1后的资产库方案
         *   B_PRIVATE_2：B用户设计库方案
         *   B_DESIGN_2：B用户发布B_PRIVATE_2后的资产库方案
         *
         * 1.只有A_PRIVATE_1、A_DESIGN_1--视图被A_PRIVATE_1、A_DESIGN_1关联：
         *   --给A分别发送A_PRIVATE_1、A_DESIGN_1视图更新消息；
         * 2.A_PRIVATE_1=>A_DESIGN_1=>B_PRIVATE_2=>B_DESIGN_2：此时A_DESIGN_1为历史版本：
         *   (1).视图被A_PRIVATE_1、A_DESIGN_1、B_PRIVATE_2、B_DESIGN_2关联：
         *      --给A发送A_PRIVATE_1视图更新消息；给B分别发送B_PRIVATE_2、B_DESIGN_2视图更新消息
         *   (2).视图被A_DESIGN_1、B_PRIVATE_2、B_DESIGN_2关联：
         *      --给A发送A_PRIVATE_1视图更新消息；给B分别发送B_PRIVATE_2、B_DESIGN_2视图更新消息
         */
        //过滤掉删除状态方案
        planDesignInstanceDTOS = planDesignInstanceDTOS.stream().filter(
                instance -> !"deleted".equals(instance.getStatus())).collect(Collectors.toList());
        List<PlanDesignInstanceDTO> sendMsgPlanList = new ArrayList<>();
        if (CollectionUtils.isEmpty(planDesignInstanceDTOS)) {
            return sendMsgPlanList;
        }
        //通过历史版本方案找到设计库方案
        List<PlanDesignInstanceDTO> historyPlanInstances = planDesignInstanceDTOS.stream().filter(instance ->
                "history".equals(instance.getStatus()) && instance.getAssetsType().equals(2)).collect(Collectors.toList());
        Map<Long, List<PlanDesignInstanceDTO>> historyKeyWithPrivatePlanMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(historyPlanInstances)) {
            List<Long> historyPlanIds = historyPlanInstances.stream().map(PlanDesignInstanceDTO::getId).collect(Collectors.toList());
            //历史版本方案对应设计库方案列表
            List<PlanDesignInstanceDTO> designPlanInstances = planDesignInstanceService.findDesignHistoryPlanList(historyPlanIds);
            historyKeyWithPrivatePlanMap = designPlanInstances.stream().collect(Collectors.groupingBy(PlanDesignInstanceDTO::getDetectionPlanId));
        }
        this.setPrivatePlanByHistory(planDesignInstanceDTOS, sendMsgPlanList, historyKeyWithPrivatePlanMap);
        return sendMsgPlanList;
    }

    private void setPrivatePlanByHistory(List<PlanDesignInstanceDTO> planDesignInstanceDTOS
            , List<PlanDesignInstanceDTO> sendMsgPlanList, Map<Long, List<PlanDesignInstanceDTO>> historyKeyWithPrivatePlanMap) {
        Set<Long> addedPlanInstanceIds = new HashSet<>();
        for (PlanDesignInstanceDTO instance : planDesignInstanceDTOS) {
            if (instance.getAssetsType() == null) {
                continue;
            }
            //私有库方案都发
            if (instance.getAssetsType().equals(1)) {
                this.addPlanInstances(addedPlanInstanceIds, instance, sendMsgPlanList);
                continue;
            }
            //资产库-历史版本方案
            if ("history".equals(instance.getStatus())) {
                this.setPrivatePlanByHistoryCaseDesignHis(historyKeyWithPrivatePlanMap, instance, addedPlanInstanceIds, sendMsgPlanList);
                continue;
            }
            //资产库只发最新版本方案
            if ("published".equals(instance.getStatus())) {
                this.addPlanInstances(addedPlanInstanceIds, instance, sendMsgPlanList);
            }
        }
    }

    private void setPrivatePlanByHistoryCaseDesignHis(Map<Long, List<PlanDesignInstanceDTO>> historyKeyWithPrivatePlanMap
            , PlanDesignInstanceDTO instance, Set<Long> addedPlanInstanceIds, List<PlanDesignInstanceDTO> sendMsgPlanList) {
        //历史版本方案对应设计库方案列表
        List<PlanDesignInstanceDTO> privateHistoryList = historyKeyWithPrivatePlanMap.get(instance.getId());
        if (CollectionUtils.isEmpty(privateHistoryList)) {
            return;
        }
        //加入历史版本方案对应的设计库方案
        for (PlanDesignInstanceDTO p : privateHistoryList) {
            this.addPlanInstances(addedPlanInstanceIds, p, sendMsgPlanList);
        }
    }

    private void addPlanInstances(Set<Long> addedPlanInstanceIds, PlanDesignInstanceDTO addInstance, List<PlanDesignInstanceDTO> sendMsgPlanList) {
        if (addInstance == null) {
            return;
        }
        if (!addedPlanInstanceIds.contains(addInstance.getId())) {
            sendMsgPlanList.add(addInstance);
            addedPlanInstanceIds.add(addInstance.getId());
        }
    }

    @Override
    @Async
    public void workflowMsgSave(String result, String sourceType, String sourceId, String startUserId, String opUser, String instanceName) {
        LOGGER.info("消息：result:{}, sourceType:{}, sourceId:{}, startUserId:{}, opUser:{}", result, sourceType, sourceId, startUserId, opUser);
        if (StringUtils.isEmpty(sourceType)) {
            return;
        }
        boolean pass = result.equals("pass") || result.equals("submit");
        String approveMsg = pass ? "通过审批" : result.equals("cancel") ? "终止审批" : result.equals("noAgree") ? "被拒绝" : "被驳回";
        WorkFlowMsgSaveParam param = WorkFlowMsgSaveParam.builder()
                .pass(pass)
                .approveMsg(approveMsg)
                .isPublic(pass ? 1 : 0)
                .sourceId(sourceId)
                .opUser(opUser)
                .instanceName(instanceName)
                .build();
        switch (sourceType) {
            case "plan":
                this.initWorkflowPlanMsgSave(param, startUserId);
                break;
            case "diagram":
                this.initWorkflowDiagramMsgSave(param, startUserId);
                break;
            case "model":
                this.initWorkflowModelMsgSave(param);
                break;
            case "archReview":
                this.initArchReviewMsgSave(param, startUserId);
                break;
            case "assert":
                this.initAssertMsgSave(param, startUserId);
                break;
            default:
                return;
        }
    }

    /**
     * 初始化方案审批消息
     * @param param
     * @param startUserId
     * @return
     */
    private void initWorkflowPlanMsgSave(WorkFlowMsgSaveParam param, String startUserId) {
        //等待方案信息同步
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
        //方案审批驳回/拒绝/终止，若评审提交人和资产创建人不一致，按原规则给评审提交人发送待办/通知；
        //若审批通过（最终结果），发布方案，发送通知至审批提交人及方案创建人
        //当前审核方案-私有库方案
        PlanDesignInstance planDesignInstance = planDesignInstanceService.getPlanDesignInstance(Long.valueOf(param.getSourceId()));
        PlanDesignInstanceDTO plan = null;
        if (planDesignInstance != null) {
            plan = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(planDesignInstance, plan);
        }
        if (plan == null) {
            LOGGER.info("消息：方案信息为空:{}", param.getSourceId());
            return;
        }
        String planId = plan.getId().toString();
        String msg = JSON.toJSONString(plan);
        LOGGER.info("消息：设计库方案信息:{}", msg);
        //审批通过，方案版本更新消息推送
        if (param.getPass()) {
            //资产库方案
            PlanDesignInstance planDesignInstanceInfo = planDesignInstanceService.getPlanDesignInstance(plan.getDetectionPlanId());
            PlanDesignInstanceDTO designPlan = null;
            if (planDesignInstanceInfo != null) {
                designPlan = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(planDesignInstanceInfo, designPlan);
            }
            if (designPlan != null) {
                planId = designPlan.getId().toString();
                msg = JSON.toJSONString(designPlan);
                LOGGER.info("消息：资产仓库方案信息:{}", msg);
                this.doPlanNewVersion(designPlan);
            }
        }
        boolean shareSubmit = !plan.getCreatorCode().equals(startUserId);
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);
        notice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE, shareSubmit ? "提交" : "创建", "方案", plan.getName(), param.getApproveMsg()));
        notice.setRead(0);
        String userName = plan.getCreatorCode();
        //协作者提交的
        if (shareSubmit) {
            userName = startUserId;
        }
        notice.setUserName(userName);
        //参数
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.PLAN_ID, planId);
        params.put(NoticeConstant.SOURCE_TYPE, param.getIsPublic());
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        keywords.add(new EamNoticeKeyword(plan.getName(), params));
        notice.setTag(NoticeConstant.TAG_PLAN);
        notice.setCustomer(NoticeConstant.TAG_PLAN);
        notice.setCustomer1(params.get(NoticeConstant.PLAN_ID).toString());
        notice.setCustomer2(param.getApproveMsg());
        notice.setCustomer3(shareSubmit ? "提交" : "创建");
        notice.setKeywords(keywords);
        //如果是协作者提交的，审批通过后要给创建人推消息
        if (shareSubmit && "通过审批".equals(param.getApproveMsg())) {
            EamNotice shareMsgNotice = EamUtil.copy(notice, EamNotice.class);
            shareMsgNotice.setId(ESUtil.getUUID());
            shareMsgNotice.setUserName(plan.getCreatorCode());
            shareMsgNotice.setIsDeleted(0);
            shareMsgNotice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
            shareMsgNotice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE, "创建", "方案", plan.getName(), param.getApproveMsg()));
            shareMsgNotice.setCustomer3("创建");
            eamNoticeDao.saveOrUpdate(shareMsgNotice);
        }
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
        eamNoticeDao.saveOrUpdate(notice);
    }

    private void initWorkflowDiagramMsgSave(WorkFlowMsgSaveParam param, String startUserId) {
        //审批中的是私有库视图
        ESDiagram diagram = esDiagramSvc.getEsDiagram(param.getSourceId(), 0);
        if (diagram == null) {
            LOGGER.info("消息：视图信息为空:{}", param.getSourceId());
            return;
        }
        String dEnergy = diagram.getDEnergy();
        if (param.getPass()) {
            dEnergy = diagram.getReleaseDiagramId();
        }
        Boolean shareSubmit = !diagram.getCreator().equals(startUserId);
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);
        notice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE, shareSubmit ? "提交" : "创建", "视图", diagram.getName(), param.getApproveMsg()));
        notice.setRead(0);
        String userName = diagram.getCreator();
        //协作者提交的
        if (shareSubmit) {
            userName = startUserId;
        }
        notice.setUserName(userName);
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.DIAGRAM_ID, dEnergy);
        params.put(NoticeConstant.SOURCE_TYPE, param.getIsPublic());
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        keywords.add(new EamNoticeKeyword(diagram.getName(), params));
        notice.setTag(NoticeConstant.TAG_DIAGRAM);
        notice.setCustomer(NoticeConstant.TAG_DIAGRAM);
        notice.setCustomer1(params.get(NoticeConstant.DIAGRAM_ID).toString());
        notice.setCustomer2(param.getApproveMsg());
        notice.setCustomer3(shareSubmit ? "提交" : "创建");
        notice.setKeywords(keywords);
        //如果是协作者提交的，审批通过后要给创建人推消息
        if (shareSubmit && "通过审批".equals(param.getApproveMsg())) {
            EamNotice shareMsgNotice = EamUtil.copy(notice, EamNotice.class);
            shareMsgNotice.setId(ESUtil.getUUID());
            shareMsgNotice.setUserName(diagram.getCreator());
            shareMsgNotice.setIsDeleted(0);
            shareMsgNotice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
            shareMsgNotice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE, "创建", "方案", diagram.getName(), param.getApproveMsg()));
            shareMsgNotice.setCustomer3("创建");
            eamNoticeDao.saveOrUpdate(shareMsgNotice);
        }
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
        eamNoticeDao.saveOrUpdate(notice);
    }

    private void initWorkflowModelMsgSave(WorkFlowMsgSaveParam param) {
        //查询视图审批关联表
        DiagramApproveRlt diagramApproveRlt = diagramApproveRltSvc.getApproveRlt(Long.valueOf(param.getSourceId()));
        if (diagramApproveRlt == null) {
            LOGGER.info("消息：视图审批关联表信息为空:{}", param.getSourceId());
            return;
        }
        //提交的目录信息
        List<EamCategory> privateCategories = categorySvc.getByIds(diagramApproveRlt.getApprovelDirList(), LibType.PRIVATE);
        if (CollectionUtils.isEmpty(privateCategories)
                || privateCategories.size() != diagramApproveRlt.getApprovelDirList().size()) {
            LOGGER.info("消息：私有库模型目录缺失:{}", JSONObject.toJSONString(diagramApproveRlt.getApprovelDirList()));
            return;
        }
        //按目录层级排序
        privateCategories.sort(Comparator.comparing(EamCategory::getDirLvl));
        //审批目录最顶层目录
        EamCategory approveTopCategory = privateCategories.get(0);
        Long dirId = approveTopCategory.getId();
        if (param.getPass()) {
            List<EamCategory> categories = categorySvc.selectListByCiCodes(approveTopCategory.getModelId(),
                    Arrays.asList(approveTopCategory.getCiCode()), null, LibType.DESIGN);
            if (CollectionUtils.isEmpty(categories)) {
                LOGGER.info("消息：未找到审批目录最顶层目录对应的资产目录:[modelId:{},ciCode{}]",
                        approveTopCategory.getModelId(), approveTopCategory.getCiCode());
                return;
            }
            categories = categories.stream().filter(category -> category.getType()
                    != CategoryTypeEnum.MODEL_ROOT.val()).collect(Collectors.toList());
            dirId = categories.get(0).getId();
        }
        //目录下的第一张视图
        ESDiagram diagram = this.getCategoryDirFirstDiagram(dirId);
        if (diagram == null) {
            LOGGER.info("消息：目录下无视图:{}}", dirId);
            return;
        }
        //查模型树
        EamMultiModelHierarchy modelHierarchy = modelHierarchySvc.getModelById(approveTopCategory.getModelId());
        if (modelHierarchy == null) {
            LOGGER.info("消息：未找到模型树:modelId{}}", approveTopCategory.getModelId());
            return;
        }
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);
        notice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE,"创建", "模型", modelHierarchy.getName(), param.getApproveMsg()));
        notice.setRead(0);
        notice.setUserName(diagramApproveRlt.getOwnerCode());
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.DIR_ID, dirId);
        params.put(NoticeConstant.SOURCE_TYPE, param.getIsPublic());
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        keywords.add(new EamNoticeKeyword(modelHierarchy.getName(), params));
        notice.setTag(NoticeConstant.TAG_MODEL);
        notice.setCustomer(NoticeConstant.TAG_MODEL);
        notice.setCustomer1(approveTopCategory.getModelId().toString());
        notice.setCustomer2(param.getApproveMsg());
        notice.setCustomer3(dirId.toString());
        notice.setKeywords(keywords);
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
        eamNoticeDao.saveOrUpdate(notice);
    }

    private void initArchReviewMsgSave(WorkFlowMsgSaveParam param, String startUserId) {
        if (StringUtils.isBlank(param.getOpUser())) {
            LOGGER.error("无流程操作人，不发消息");
            return;
        }
        if (StringUtils.isBlank(param.getInstanceName())) {
            LOGGER.error("无流程名称，不发消息");
            return;
        }
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);

        CSysUser cdt = new CSysUser();
        cdt.setLoginCodeEqual(param.getOpUser());
        List<SysUser> sysUsers = userApiSvc.getSysUserByCdt(cdt);
        if (CollectionUtils.isEmpty(sysUsers)) {
            LOGGER.error("未找到流程操作人，不发消息");
            return;
        }
        SysUser opUser = sysUsers.get(0);
        String msg = "已".concat(param.getApproveMsg());
        if ("被驳回".equals(param.getApproveMsg())) {
            msg = "被".concat(opUser.getUserName()).concat("驳回，请及时查看");
        }
        notice.setContent(String.format(NoticeConstant.ARCH_REVIEW_TEMPLATE, param.getInstanceName(), msg));
        notice.setRead(0);
        notice.setUserName(startUserId);
        //跳转参数
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.SOURCE_TYPE, 0);
        params.put(NoticeConstant.ARCH_REVIEW_ID, param.getSourceId());
        keywords.add(new EamNoticeKeyword(param.getInstanceName(), params));

        notice.setTag(NoticeConstant.TAG_ARCH_REVIEW);
        notice.setCustomer(param.getOpUser());
        notice.setKeywords(keywords);
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);
        eamNoticeDao.saveOrUpdate(notice);
    }

    private void initAssertMsgSave(WorkFlowMsgSaveParam param, String startUserId) {
        CCcCi ciCdt = new CCcCi();
        ciCdt.setOwnerCodeEqual(startUserId);
        ciCdt.setId(Long.valueOf(param.getSourceId()));
        List<CcCiInfo> ciInfos = ciSwitchSvc.queryCiInfoList(1L, ciCdt, null, false, true, LibType.PRIVATE);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(ciInfos)) {
            LOGGER.error("未找到资产信息，不发消息：businessKey:{}, ownerCode:{}", param.getSourceId(), startUserId);
            return;
        }

        CcCiInfo ciInfo = ciInfos.get(0);
        List<String> ciLabels = JSONArray.parseArray(ciInfo.getCi().getCiLabel(), String.class);
        String assertName = String.join(",", ciLabels);

        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);
        notice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE, "创建", "资产", assertName, param.getApproveMsg()));
        notice.setRead(0);
        notice.setUserName(startUserId);
        notice.setTag(NoticeConstant.TAG_ASSERT);
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_WORKFLOW);

        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        keywords.add(new EamNoticeKeyword("", params));
        notice.setKeywords(keywords);

        eamNoticeDao.saveOrUpdate(notice);
    }

    /**
     * 方案版本更新消息推送
     * @param plan
     */
    private void doPlanNewVersion(PlanDesignInstanceDTO plan) {
        //获取当前资产库方案已发布的历史方案
        List<PlanDesignInstanceDTO> orignDTOS = planDesignInstanceService.findRenewVersionPlanList(plan.getId());
        String msg = JSON.toJSONString(orignDTOS);
        LOGGER.info("当前资产库方案已发布的历史方案:{}", msg);
        if (CollectionUtils.isEmpty(orignDTOS)) {
            return;
        }
        //第一次发布的方案不推送方案版本更新消息
        if (orignDTOS.size() == 1 && plan.getId().equals(orignDTOS.get(0).getId())) {
            return;
        }
        orignDTOS.sort(Comparator.comparing(PlanDesignInstanceDTO::getCreateTime).reversed());
        //发布人分组
        Map<String, List<PlanDesignInstanceDTO>> groupByCreatorCode =
                orignDTOS.stream().collect(Collectors.groupingBy(PlanDesignInstanceDTO::getCreatorCode));
        List<EamNotice> notices = new ArrayList<>();
        EamNotice notice;
        for (Map.Entry<String, List<PlanDesignInstanceDTO>> entry: groupByCreatorCode.entrySet()) {
            //同一发布人取当前人最新发布的方案
            PlanDesignInstanceDTO orignDTO = entry.getValue().get(0);
            notice = new EamNotice();
            notice.setId(ESUtil.getUUID());
            notice.setDomainId(DEFAULT_DOMAIN_ID);
            notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
            notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
            notice.setContent(String.format(NoticeConstant.PLAN_NEWV_VERSION_CONTENT_TEMPLATE, orignDTO.getName(), NoticeConstant.PLAN_NEWV_VERSION_CONTENT_TEMPLATE_KEYWORD));
            notice.setRead(0);
            notice.setUserName(orignDTO.getCreatorCode());

            //原始方案跳转参数
            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> orignParams = new ConcurrentHashMap<>();
            orignParams.put(NoticeConstant.PLAN_ID, orignDTO.getId().toString());
            orignParams.put(NoticeConstant.SOURCE_TYPE, 1);
            keywords.add(new EamNoticeKeyword(orignDTO.getName(), orignParams));

            //最新方案跳转参数
            Map<String, Object> newParams = new ConcurrentHashMap<>();
            newParams.put(NoticeConstant.PLAN_ID, plan.getBusinessKey());
            newParams.put(NoticeConstant.SOURCE_TYPE, 1);
            keywords.add(new EamNoticeKeyword(NoticeConstant.PLAN_NEWV_VERSION_CONTENT_TEMPLATE_KEYWORD, newParams));

            notice.setKeywords(keywords);
            notice.setTag(NoticeConstant.TAG_PLAN);
            notice.setIsDeleted(0);
            notice.setMsgType(NoticeConstant.MSG_TYPE_PLAN_NEWVERSION);
            notice.setCustomer(orignDTO.getId().toString());
            notice.setCustomer1(plan.getBusinessKey());
            //目录改造之后不再维护资产dirType
            //notice.setCustomer2(plan.getDirType().toString());
            notices.add(notice);
        }
        eamNoticeDao.saveOrUpdateBatch(notices);
    }

    @Override
    public void updateRead(String noticeType) {
        this.checkNoticeType(noticeType);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery(NoticeConstant.USERNAME_KEYWORDS, SysUtil.getCurrentUserInfo().getLoginCode()));
        boolQuery.must(QueryBuilders.termQuery("type.keyword", noticeType));
        eamNoticeDao.updateByQuery(boolQuery, "ctx._source.read=1", true);
    }

    @Override
    public NoticeVo noticeNum() {
        NoticeVo result = new NoticeVo();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery(NoticeConstant.USERNAME_KEYWORDS, SysUtil.getCurrentUserInfo().getLoginCode()));
        boolQuery.must(QueryBuilders.termQuery("isDeleted", 0));
        List<EamNotice> currUserNotices = eamNoticeDao.getListByQuery(boolQuery);
        Map<String, List<EamNotice>> groupByType = currUserNotices.stream().collect(Collectors.groupingBy(EamNotice::getType));
        List<EamNotice> messages = groupByType.getOrDefault(NoticeConstant.NOTICE_TYPE_MSG, new ArrayList<>());
        List<EamNotice> notices = groupByType.getOrDefault(NoticeConstant.NOTICE_TYPE_NOTICE, new ArrayList<>());
        result.setMessageCount(messages.size());
        result.setNoticeCount(notices.size());
        result.setMsgUnreadCount(messages.size() - messages.stream().mapToInt(EamNotice::getRead).reduce(Integer::sum).orElse(0));
        result.setNoticeUnreadCount(notices.size() - notices.stream().mapToInt(EamNotice::getRead).reduce(Integer::sum).orElse(0));
        return result;
    }

    @Override
    public Page<EamNoticeVo> list(String noticeType, Integer pageSize, Integer pageNum) {
        this.checkNoticeType(noticeType);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termQuery(NoticeConstant.USERNAME_KEYWORDS, SysUtil.getCurrentUserInfo().getLoginCode()));
        boolQuery.must(QueryBuilders.termQuery("type.keyword", noticeType));
        boolQuery.must(QueryBuilders.termQuery("isDeleted", 0));
        Page<EamNotice> page = eamNoticeDao.getSortListByQuery(pageNum, pageSize, boolQuery, "createTime", false);
        if (CollectionUtils.isEmpty(page.getData())) {
            return new Page<>(pageNum, pageSize, 0, 0, new ArrayList<>());
        }
        List<EamNotice> notices = page.getData();
        EamNoticeListQueryParams params = EamNoticeListQueryParams.builder()
                .planVersionList(new ArrayList<>())
                .planIds(new HashSet<>())
                .diagramIds(new HashSet<>())
                .userIds(new HashSet<>())
                .modelIds(new HashSet<>())
                .dirIds(new HashSet<>())
                .build();
        for (EamNotice notice : notices) {
            if (StringUtils.isBlank(notice.getMsgType())) {
                continue;
            }
            this.fillParams(notice, params);
        }
        params.setBusinessKeyPlanMap(this.getBusinessKeyPlanMap(params.getPlanVersionList()));
        params.setPlanMap(this.getPlanMap(params.getPlanIds()));
        params.setDiagramMap(this.getDiagramMap(params.getDiagramIds()));
        params.setUserMap(this.getUserMap(params.getUserIds()));
        params.setModelMap(this.getModelMap(params.getModelIds()));
        List<EamNoticeVo> lists = EamUtil.copy(notices, EamNoticeVo.class);
        this.replaceNewVersionName(lists, params);
        return new Page<>(pageNum, pageSize, page.getTotalRows(), page.getTotalPages(), lists);
    }

    private void fillParams(EamNotice notice, EamNoticeListQueryParams params) {
        PlanVersionDTO planVersion;
        switch (notice.getMsgType()) {
            case NoticeConstant.MSG_TYPE_PLAN_DIAGRAM_UPDATE:
                if ("0".equals(notice.getCustomer())) {
                    params.getPlanIds().add(Long.valueOf(notice.getCustomer1()));
                    break;
                }
                planVersion = new PlanVersionDTO();
                planVersion.setBusinessKey(notice.getCustomer1());
                params.getPlanVersionList().add(planVersion);
                break;
            case NoticeConstant.MSG_TYPE_PLAN_NEWVERSION:
                params.getPlanIds().add(Long.valueOf(notice.getCustomer()));
                break;
            case NoticeConstant.MSG_TYPE_WORKFLOW:
                if (NoticeConstant.TAG_PLAN.equals(notice.getCustomer())) {
                    params.getPlanIds().add(Long.valueOf(notice.getCustomer1()));
                } else if (NoticeConstant.TAG_DIAGRAM.equals(notice.getCustomer())) {
                    params.getDiagramIds().add(notice.getCustomer1());
                } else if (NoticeConstant.TAG_MODEL.equals(notice.getCustomer())) {
                    params.getModelIds().add(Long.valueOf(notice.getCustomer1()));
                }
                break;
            case NoticeConstant.MSG_TYPE_SHARE:
                if (NoticeConstant.TAG_PLAN.equals(notice.getCustomer())) {
                    params.getPlanIds().add(Long.valueOf(notice.getCustomer2()));
                } else {
                    params.getDiagramIds().add(notice.getCustomer2());
                }
                params.getUserIds().add(Long.valueOf(notice.getCustomer1()));
                break;
            case NoticeConstant.MSG_TYPE_DEVL_TMPLATE:
                params.getPlanIds().add(Long.valueOf(notice.getCustomer()));
                break;
            case NoticeConstant.MSG_TYPE_SHARE_COLLABORATE:
                params.getPlanIds().add(Long.valueOf(notice.getCustomer2()));
                params.getUserIds().add(Long.valueOf(notice.getCustomer1()));
                break;
            case NoticeConstant.MSG_TYPE_COMPLETE_COLLABORATE:
                params.getPlanIds().add(Long.valueOf(notice.getCustomer2()));
                params.getUserIds().add(Long.valueOf(notice.getCustomer1()));
                break;
            case NoticeConstant.MSG_TYPE_SHARE_PUBLISH_ASSERT:
                params.getUserIds().add(Long.valueOf(notice.getCustomer()));
                if (NoticeConstant.TAG_PLAN.equals(notice.getTag())) {
                    params.getPlanIds().add(Long.valueOf(notice.getCustomer1()));
                } else {
                    params.getDiagramIds().add(notice.getCustomer1());
                }
                break;
            case NoticeConstant.MSG_TYPE_ARCH_REVIEW_CIRCULATE:
                params.getUserIds().add(Long.valueOf(notice.getCustomer()));
                break;
            case NoticeConstant.MSG_TYPE_PLAN_PUBLISH_FAIL:
                params.getPlanIds().add(Long.valueOf(notice.getCustomer1()));
                break;
            default:
                break;
        }
    }

    private Map<String, PlanDesignInstanceDTO> getBusinessKeyPlanMap(List<PlanVersionDTO> planVersionList) {
        Map<String, PlanDesignInstanceDTO> businessKeyPlanMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(planVersionList)) {
            List<PlanDesignInstanceDTO> planDesignInstances = planDesignInstanceService.findAssetsLatestPlanList(planVersionList);
            businessKeyPlanMap = planDesignInstances.stream().collect(Collectors.toMap(PlanDesignInstanceDTO::getBusinessKey, e -> e, (k1, k2) -> k1));
        }
        return businessKeyPlanMap;
    }

    private Map<Long, PlanDesignInstanceDTO> getPlanMap(Set<Long> planIds) {
        Map<Long, PlanDesignInstanceDTO> planMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(planIds)) {
            List<PlanDesignInstance> planDesignInstances = planDesignInstanceService.getByIds(planIds);
            List<PlanDesignInstanceDTO> planDesigns = new ArrayList<>();
            for (PlanDesignInstance instance : planDesignInstances) {
                PlanDesignInstanceDTO planDesignInstanceDTO = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(instance, planDesignInstanceDTO);
                planDesigns.add(planDesignInstanceDTO);
            }
            if (!CollectionUtils.isEmpty(planDesigns)) {
                planMap = planDesigns.stream().collect(Collectors.toMap(PlanDesignInstanceDTO::getId, e -> e));
            }
        }
        return planMap;
    }

    private Map<String, ESDiagram> getDiagramMap(Set<String> diagramIds) {
        Map<String, ESDiagram> diagramMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(diagramIds)) {
            List<ESDiagram> diagrams = esDiagramSvc.queryDBDiagramInfoByIds(diagramIds.toArray(new String[diagramIds.size()]));
            if (!CollectionUtils.isEmpty(diagrams)) {
                diagramMap = diagrams.stream().collect(Collectors.toMap(ESDiagram::getDEnergy, e -> e));
            }
        }
        return diagramMap;
    }

    private Map<Long, SysUser> getUserMap(Set<Long> userIds) {
        Map<Long, SysUser> userMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(userIds)) {
            CSysUser cdt = new CSysUser();
            cdt.setIds(userIds.toArray(new Long[userIds.size()]));
            List<SysUser> users = userApiSvc.getSysUserByCdt(cdt);
            if (!CollectionUtils.isEmpty(users)) {
                userMap = users.stream().collect(Collectors.toMap(SysUser::getId, e -> e));
            }
        }
        return userMap;
    }

    private Map<Long, EamMultiModelHierarchy> getModelMap(Set<Long> modelIds) {
        Map<Long, EamMultiModelHierarchy> modelMap = new ConcurrentHashMap<>();
        if (!CollectionUtils.isEmpty(modelIds)) {
            List<EamMultiModelHierarchy> modelHierarchies = modelHierarchySvc.getModelByIds(modelIds);
            if (!CollectionUtils.isEmpty(modelHierarchies)) {
                modelMap = modelHierarchies.stream().collect(Collectors.toMap(EamMultiModelHierarchy::getId, e -> e));
            }
        }
        return modelMap;
    }

    private ESDiagram getCategoryDirFirstDiagram(Long dirId) {
        BoolQueryBuilder diagramQuery = QueryBuilders.boolQuery();
        diagramQuery.must(QueryBuilders.termQuery("status", 1));
        diagramQuery.must(QueryBuilders.termQuery("dirId", dirId));
        Page<ESDiagram> diagramPage = esDiagramSvc.selectListByQuery(1, 3000, diagramQuery);
        List<ESDiagram> diagrams = diagramPage.getData();
        if (CollectionUtils.isEmpty(diagrams)) {
            return null;
        }
        //先按视图类型排序(如果存在主视图，主视图始终在第一个),然后按修改时间倒序
        diagrams.sort(Comparator.comparing(ESDiagram::getDiagramSubType)
                .thenComparing(ESDiagram::getModifyTime).reversed());
        return diagrams.get(0);
    }

    private void replaceNewVersionName(List<EamNoticeVo> notices, EamNoticeListQueryParams params) {
        for (EamNoticeVo notice : notices) {
            if (StringUtils.isBlank(notice.getMsgType())) {
                continue;
            }
            switch (notice.getMsgType()) {
                case NoticeConstant.MSG_TYPE_PLAN_DIAGRAM_UPDATE:
                    this.replaceNameCasePlanDiagramUpdate(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_PLAN_NEWVERSION:
                    this.replaceNameCasePlanNewVersion(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_WORKFLOW:
                    this.replaceNameCaseWorkflow(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_SHARE:
                    this.replaceNameCaseShare(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_DEVL_TMPLATE:
                    this.replaceNameCaseDevlTmplateUpdate(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_SHARE_COLLABORATE:
                    this.replaceNameShareCollaborate(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_COMPLETE_COLLABORATE:
                    this.replaceNameCompleteCollaborate(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_SHARE_PUBLISH_ASSERT:
                    this.replaceNameSharePublishAssert(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_ARCH_REVIEW_CIRCULATE:
                    this.replaceNameArchReviewCirCulate(notice, params);
                    break;
                case NoticeConstant.MSG_TYPE_PLAN_PUBLISH_FAIL:
                    this.replaceNamePlanPublishFail(notice, params);
                    break;
                default:
                    break;
            }
        }
    }

    private void replaceNameCasePlanDiagramUpdate(EamNoticeVo notice, EamNoticeListQueryParams params) {
        PlanDesignInstanceDTO planDesign = "0".equals(notice.getCustomer()) ?
                params.getPlanMap().get(Long.valueOf(notice.getCustomer1())) :
                params.getBusinessKeyPlanMap().get(notice.getCustomer1());
        if (planDesign != null) {
            List<EamNoticeKeyword> keywords = notice.getKeywords();
            keywords.get(0).setName(planDesign.getName());
            notice.setContent(String.format("0".equals(notice.getCustomer()) ?
                    NoticeConstant.PLAN_DIAGRAM_UPDATE_PRIVATE_TEMPLATE :
                    NoticeConstant.PLAN_DIAGRAM_UPDATE_DESIGN_TEMPLATE, planDesign.getName()));
        }
    }

    private void replaceNameCasePlanNewVersion(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer()));
        if (planDesign != null) {
            keywords.get(0).setName(planDesign.getName());
            notice.setContent(String.format(NoticeConstant.PLAN_NEWV_VERSION_CONTENT_TEMPLATE,
                    planDesign.getName(), NoticeConstant.PLAN_NEWV_VERSION_CONTENT_TEMPLATE_KEYWORD));
        }
    }

    private void replaceNameCaseWorkflow(EamNoticeVo notice, EamNoticeListQueryParams params) {
        if (NoticeConstant.TAG_ARCH_REVIEW.equals(notice.getTag())
                || NoticeConstant.TAG_ASSERT.equals(notice.getTag())) {
            return;
        }
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        String tagName = "";
        if (NoticeConstant.TAG_PLAN.equals(notice.getTag())) {
            PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer1()));
            if (planDesign != null) {
                keywords.get(0).setName(planDesign.getName());
            }
            tagName = "方案";
        } else if (NoticeConstant.TAG_DIAGRAM.equals(notice.getTag())) {
            ESDiagram esDiagram = params.getDiagramMap().get(notice.getCustomer1());
            if (esDiagram != null) {
                keywords.get(0).setName(esDiagram.getName());
                notice.setFlowStatus(esDiagram.getFlowStatus());
            }
            tagName = "视图";
        } else {
            Long modelId = Long.valueOf(notice.getCustomer1());
            EamMultiModelHierarchy multiModelHierarchy = params.getModelMap().get(modelId);
            if (multiModelHierarchy != null) {
                keywords.get(0).setName(multiModelHierarchy.getName());
            }
            tagName = "模型";
        }
        String action = notice.getCustomer3();
        if (StringUtils.isBlank(action)) {
            action = "创建";
        }
        notice.setContent(String.format(NoticeConstant.WORKFLOW_CONTENT_TEMPLATE,
                action, tagName, keywords.get(0).getName(), notice.getCustomer2()));
    }

    private void replaceNameCaseShare(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        SysUser user = params.getUserMap().get(Long.valueOf(notice.getCustomer1()));
        if (user != null) {
            notice.setCustomer3(user.getUserName());
        }
        if (NoticeConstant.TAG_PLAN.equals(notice.getCustomer())) {
            PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer2()));
            if (planDesign != null) {
                keywords.get(0).setName(planDesign.getName());
            }
        } else {
            ESDiagram esDiagram = params.getDiagramMap().get(notice.getCustomer2());
            if (esDiagram != null) {
                keywords.get(0).setName(esDiagram.getName());
            }
        }
        String tag = NoticeConstant.TAG_PLAN.equals(notice.getCustomer()) ? "方案" : "视图";
        notice.setContent(String.format(NoticeConstant.SHARE_CONTENT_TEMPLATE,
                notice.getCustomer3(), tag + keywords.get(0).getName()));
    }

    private void replaceNameCompleteCollaborate(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer2()));
        ChapterInstance planChapterInstance = null;
        if (!StringUtils.isEmpty(notice.getCustomer())) {
            planChapterInstance = planChapterInstanceService.getPlanChapterInstance(Long.valueOf(notice.getCustomer()));
        }
        if (planDesign != null && planChapterInstance != null) {
            keywords.get(0).setName(planDesign.getName());
            keywords.get(1).setName(planChapterInstance.getName());
            notice.setContent(String.format(NoticeConstant.PLAN_CHAPTER_COMPLETE_COLLABORATE,
                    notice.getCustomer3(), planDesign.getName(), planChapterInstance.getName()));
        }
    }

    private void replaceNameSharePublishAssert(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        String assertName = notice.getCustomer2();
        if (NoticeConstant.TAG_PLAN.equals(notice.getTag())) {
            PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer1()));
            if (planDesign != null) {
                assertName = planDesign.getName();
            }
        } else {
            ESDiagram diagram = params.getDiagramMap().get(notice.getCustomer1());
            if (diagram != null) {
                assertName = diagram.getName();
            }
        }
        String shareUserName = notice.getCustomer3();
        SysUser shareUser = params.getUserMap().get(Long.valueOf(notice.getCustomer()));
        if (shareUser != null) {
            shareUserName = shareUser.getUserName();
        }
        keywords.get(0).setName(assertName);
        notice.setContent(String.format(NoticeConstant.SHARE_PUBLISH_ASSERT,
                NoticeConstant.TAG_DIAGRAM.equals(notice.getTag()) ? "视图" : "方案", assertName, shareUserName));
    }

    private void replaceNameArchReviewCirCulate(EamNoticeVo notice, EamNoticeListQueryParams params) {
        String creatorName = notice.getCustomer1();
        SysUser creator = params.getUserMap().get(Long.valueOf(notice.getCustomer()));
        if (creator != null) {
            creatorName = creator.getUserName();
        }
        String itemName = notice.getCustomer2();
        notice.setContent(String.format(NoticeConstant.ARCH_REVIEW_CIRCULATE_TEMPLATE, creatorName, itemName));
    }

    private void replaceNamePlanPublishFail(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        String planName = notice.getCustomer();
         PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer1()));
         if (planDesign != null) {
             planName = planDesign.getName();
         }
        keywords.get(0).setName(planName);
        notice.setContent(String.format(NoticeConstant.PLAN_PUBLISH_FAIL, planName));
    }

    private void replaceNameShareCollaborate(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer2()));
        ChapterInstance planChapterInstance = null;
        if (!StringUtils.isEmpty(notice.getCustomer())) {
            planChapterInstance = planChapterInstanceService.getPlanChapterInstance(Long.valueOf(notice.getCustomer()));
        }
        if (planDesign != null && planChapterInstance != null) {
            keywords.get(0).setName(planDesign.getName());
            keywords.get(1).setName(planChapterInstance.getName());
            notice.setContent(String.format(NoticeConstant.PLAN_CHAPTER_SHARE_COLLABORATE, notice.getCustomer3(), planDesign.getName(), planChapterInstance.getName()));
        }
    }

    private void replaceNameCaseDevlTmplateUpdate(EamNoticeVo notice, EamNoticeListQueryParams params) {
        List<EamNoticeKeyword> keywords = notice.getKeywords();
        PlanDesignInstanceDTO planDesign = params.getPlanMap().get(Long.valueOf(notice.getCustomer()));
        if (planDesign != null) {
            keywords.get(0).setName(planDesign.getName());
            notice.setContent(String.format(NoticeConstant.DEV_TEMPLATE_UPDATE_CONTENT_TEMPLATE,
                    notice.getCustomer1().equals("0") ? "本地" : "发布", planDesign.getName()));
        }
    }

    private void checkNoticeType(String noticeType) {
        if (!noticeType.equals(NoticeConstant.NOTICE_TYPE_MSG) && !noticeType.equals(NoticeConstant.NOTICE_TYPE_NOTICE)) {
            throw new BinaryException("参数错误");
        }
    }

    @Override
    public RemoteResult transform(EamNoticeTransVo noticeTransVo) {
        EamNotice eamNotice = eamNoticeDao.getById(noticeTransVo.getId());
        if (eamNotice == null) {
            return new RemoteResult(noticeTransVo.getTransId());
        }
        //分享消息处理
        if (StringUtils.isNotBlank(eamNotice.getMsgType())
                && eamNotice.getMsgType().equals(NoticeConstant.MSG_TYPE_SHARE)) {
            return this.getShareMsgTrans(eamNotice, noticeTransVo);
        }
        //工作流模型审批消息处理
        if (StringUtils.isNotBlank(eamNotice.getMsgType())
                && eamNotice.getMsgType().equals(NoticeConstant.MSG_TYPE_WORKFLOW)
                && eamNotice.getTag().equals(NoticeConstant.TAG_MODEL)) {
            return this.getModelApproveTrans(eamNotice);
        }
        if (!eamNotice.getTag().equals(NoticeConstant.TAG_PLAN)) {
            return new RemoteResult(noticeTransVo.getTransId());
        }
        List<EamNoticeKeyword> keywords = eamNotice.getKeywords();
        for (EamNoticeKeyword keyword : keywords) {
            Map<String, Object> params = keyword.getParams();
            if (Integer.valueOf(params.get(NoticeConstant.SOURCE_TYPE).toString()) == 1) {
                if (isLongTransId(params)) {
                    continue;
                }
                String businssKey = params.get(NoticeConstant.PLAN_ID).toString();
                if (noticeTransVo.getTransId().equals(businssKey)) {
                    //通过businessKey + dirType获取最新版本方案
                    PlanDesignInstanceDTO planInstance = planDesignInstanceService.getAssetsLatestPlan(businssKey, null);
                    if (planInstance == null) {
                        return new RemoteResult(false, 30001, NoticeConstant.PLAN_DELETE_MSG);
                    }
                    noticeTransVo.setTransId(planInstance.getId().toString());
                }
            }
        }
        return new RemoteResult(noticeTransVo.getTransId());
    }

    private boolean isLongTransId(Map<String, Object> params) {
        boolean isLong = false;
        try {
            Long.valueOf(params.get(NoticeConstant.PLAN_ID).toString());
            isLong = true;
        } catch (Exception e) {
            String msg = params.get(NoticeConstant.PLAN_ID) + "";
            LOGGER.info("历史方案:{}", msg);
        }
        return isLong;
    }

    private RemoteResult getShareMsgTrans(EamNotice notice, EamNoticeTransVo noticeTransVo) {
        if (notice.getTag().equals(NoticeConstant.TAG_DIAGRAM)) {
            return this.getShareMsgTransCaseDiagram(notice, noticeTransVo);
        }
        return this.getShareMsgTransCasePlan(notice, noticeTransVo);
    }

    private RemoteResult getModelApproveTrans(EamNotice notice) {
        Map<String, Object> params = notice.getKeywords().get(0).getParams();
        int sourceType = Integer.parseInt(params.get(NoticeConstant.SOURCE_TYPE).toString());
        LibType libType = sourceType == 0 ? LibType.PRIVATE : LibType.DESIGN;
        Long dirId = Long.valueOf(notice.getCustomer3());
        EamCategory category = categorySvc.getById(dirId, libType);
        if (category == null) {
            return new RemoteResult(false, 30002, "目录已被删除");
        }
        ESDiagram esDiagram = this.getCategoryDirFirstDiagram(dirId);
        if (esDiagram == null) {
            return new RemoteResult(false, 30002, "视图已被删除");
        }
        return new RemoteResult(esDiagram.getDEnergy());
    }

    private RemoteResult getShareMsgTransCaseDiagram(EamNotice notice, EamNoticeTransVo noticeTransVo) {
        String [] diagramDEngry = new String[1];
        diagramDEngry[0] = notice.getCustomer2();
        List<ESDiagram> esDiagrams = esDiagramSvc.queryDBDiagramInfoByIds(diagramDEngry);
        if (CollectionUtils.isEmpty(esDiagrams)) {
            return new RemoteResult(false, 30002, "视图已被删除");
        }
        ESDiagram diagram = esDiagrams.get(0);
        if (diagram.getStatus() == 0 || diagram.getDataStatus() == 0) {
            return new RemoteResult(false, 30002, "视图已被删除");
        }
        //是否存在权限
        DiagramShareRecord diagramShareRecord = shareDiagramSvc.queryShare(diagram.getId(), SysUtil.getCurrentUserInfo().getId());
        if (diagramShareRecord == null) {
            UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(diagram.getCreator());
            if (userInfo == null) {
                LOGGER.info("未找到创建者:{}", diagram.getCreator());
                return new RemoteResult(false, 30003, "未找到创建者");
            }
            return new RemoteResult(false, 30003, "您的分享权限已被删除，请联系作者" + userInfo.getUserName() + "重新分享。");
        }
        return new RemoteResult(noticeTransVo.getTransId());
    }

    private RemoteResult getShareMsgTransCasePlan(EamNotice notice, EamNoticeTransVo noticeTransVo) {
        PlanDesignInstance planDesignInstance = planDesignInstanceService.getPlanDesignInstance(Long.valueOf(notice.getCustomer2()));
        PlanDesignInstanceDTO plan = null;
        if (planDesignInstance != null) {
            plan = new PlanDesignInstanceDTO();
            BeanUtils.copyProperties(planDesignInstance, plan);
        }
        if (plan == null) {
            return new RemoteResult(false, 30001, NoticeConstant.PLAN_DELETE_MSG);
        }
        if (plan.getStatus() == null || plan.getStatus().equals("deleted")) {
            return new RemoteResult(false, 30001, NoticeConstant.PLAN_DELETE_MSG);
        }
        //获取方案协作者
        List<PlanDesignShareRecordDTO> planDesignShareRecords = planDesignInstanceService.findShareRecordList(Long.valueOf(notice.getCustomer2()));
        Set<String> sharedLoginCodes = new HashSet<>();
        if (!CollectionUtils.isEmpty(planDesignShareRecords)) {
            sharedLoginCodes = planDesignShareRecords.stream().map(PlanDesignShareRecordDTO::getSharedLoginCode).collect(Collectors.toSet());
        }
        if (!sharedLoginCodes.contains(SysUtil.getCurrentUserInfo().getLoginCode())) {
            UserInfo userInfo = userApiSvc.getUserInfoByLoginCode(plan.getCreatorCode());
            if (userInfo == null) {
                LOGGER.info("未找到创建者:{}", plan.getCreatorCode());
                return new RemoteResult(false, 30003, "未找到创建者");
            }
            return new RemoteResult(false, 30003, "您的分享权限已被删除，请联系作者" + userInfo.getUserName() + "重新分享。");
        }
        return new RemoteResult(noticeTransVo.getTransId());
    }

    @Override
    public void shareMsgSave(List<ShareMsgDTO> shareMsgDTOS) {
        if (CollectionUtils.isEmpty(shareMsgDTOS)) {
            return;
        }
        String sourceName;
        String viewType = "";
        if (shareMsgDTOS.get(0).getSourceType().equals(NoticeConstant.TAG_DIAGRAM)) {
            String []diagramIds = new String[1];
            diagramIds[0] = shareMsgDTOS.get(0).getSourceId();
            List<ESDiagram> diagrams = esDiagramSvc.queryDBDiagramInfoByIds(diagramIds);
            if (CollectionUtils.isEmpty(diagrams)) {
                LOGGER.info("消息，未查到视图信息，结束:{}", shareMsgDTOS.get(0).getSourceId());
                return;
            }
            sourceName = diagrams.get(0).getName();
            viewType = diagrams.get(0).getViewType();
        } else {
            PlanDesignInstance planDesignInstance = planDesignInstanceService.getPlanDesignInstance(Long.valueOf(shareMsgDTOS.get(0).getSourceId()));
            PlanDesignInstanceDTO planDesign = null;
            if (planDesignInstance != null) {
                planDesign = new PlanDesignInstanceDTO();
                BeanUtils.copyProperties(planDesignInstance, planDesign);
            }
            if (planDesign == null) {
                LOGGER.info("消息，未查到方案信息，结束:{}", shareMsgDTOS.get(0).getSourceId());
                return;
            }
            sourceName = planDesign.getName();
        }
        CSysUser userParms = new CSysUser();
        userParms.setId(shareMsgDTOS.get(0).getOwnerId());
        List<SysUser> users = userApiSvc.getSysUserByCdt(userParms);
        if (CollectionUtils.isEmpty(users)) {
            LOGGER.info("消息，未查到分享人信息，结束:{}", shareMsgDTOS.get(0).getOwnerId());
            return;
        }
        SysUser owner = users.get(0);
        userParms = new CSysUser();
        List<Long> userIds = shareMsgDTOS.stream().map(ShareMsgDTO::getSharedUserId).collect(Collectors.toList());
        userParms.setIds(userIds.toArray(new Long[userIds.size()]));
        List<SysUser> shareUsers = userApiSvc.getSysUserByCdt(userParms);
        if (CollectionUtils.isEmpty(shareUsers) || shareUsers.size() != userIds.size()) {
            String msg = JSON.toJSONString(userIds);
            LOGGER.info("消息，未查到被分享人信息，结束:{}", msg);
            return;
        }
        Map<Long, SysUser> userMap = shareUsers.stream().collect(Collectors.toMap(SysUser::getId, e -> e));
        List<EamNotice> notices = this.getShareMsgSaveList(shareMsgDTOS, userMap, viewType, owner, sourceName);
        eamNoticeDao.saveOrUpdateBatch(notices);
    }

    private List<EamNotice> getShareMsgSaveList(List<ShareMsgDTO> shareMsgDTOS, Map<Long, SysUser> userMap, String viewType, SysUser owner, String sourceName) {
        List<EamNotice> notices = new ArrayList<>();
        for (ShareMsgDTO share : shareMsgDTOS) {
            EamNotice notice = new EamNotice();
            notice.setId(ESUtil.getUUID());
            notice.setDomainId(DEFAULT_DOMAIN_ID);
            notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
            notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
            notice.setRead(0);
            notice.setMsgType(NoticeConstant.MSG_TYPE_SHARE);
            notice.setUserName(userMap.get(share.getSharedUserId()).getLoginCode());
            //跳转参数
            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> params = new ConcurrentHashMap<>();
            params.put(NoticeConstant.SOURCE_TYPE, 0);
            if (share.getSourceType().equals(NoticeConstant.TAG_DIAGRAM)) {
                notice.setTag(NoticeConstant.TAG_DIAGRAM);
                params.put(NoticeConstant.DIAGRAM_ID, share.getSourceId());
                if (viewType != null) {
                    params.put(NoticeConstant.VIEW_TYPE, viewType);
                }
                notice.setContent(String.format(NoticeConstant.SHARE_CONTENT_TEMPLATE, owner.getUserName(), "视图" + sourceName));
            } else {
                notice.setTag(NoticeConstant.TAG_PLAN);
                params.put(NoticeConstant.PLAN_ID, share.getSourceId());
                notice.setContent(String.format(NoticeConstant.SHARE_CONTENT_TEMPLATE, owner.getUserName(), "方案" + sourceName));
            }
            keywords.add(new EamNoticeKeyword(sourceName, params));
            notice.setKeywords(keywords);
            notice.setCustomer(notice.getTag());
            notice.setCustomer1(share.getOwnerId().toString());
            notice.setCustomer2(share.getSourceId());
            notice.setCustomer3(owner.getUserName());
            notice.setIsDeleted(0);
            notices.add(notice);
        }
        return notices;
    }

    @Override
    public void deliverableTemplataMsgSave(DeliTemplateMsgSaveVo saveVo) {
        if (saveVo == null || saveVo.getId() == null) {
            LOGGER.info("消息，缺失参数 结束");
            return;
        }
        //使用当前交付物模板的方案
        List<PlanDesignInstanceDTO> planDesignInstanceDTOS = planDesignInstanceService.findByTemplateId(saveVo.getId());
        if (CollectionUtils.isEmpty(planDesignInstanceDTOS)) {
            LOGGER.info("消息，交付物模板未被关联方案使用，结束：{}", saveVo.getId());
            return;
        }
        List<EamNotice> notices = new ArrayList<>();
        for (PlanDesignInstanceDTO plan : planDesignInstanceDTOS) {
            if (plan.getAssetsType() == null) {
                String msg = JSON.toJSONString(plan);
                LOGGER.info("消息，数据错误，跳过:{}", msg);
                continue;
            }
            EamNotice notice = new EamNotice();
            notice.setId(ESUtil.getUUID());
            notice.setDomainId(DEFAULT_DOMAIN_ID);
            notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
            notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
            notice.setContent(String.format(NoticeConstant.DEV_TEMPLATE_UPDATE_CONTENT_TEMPLATE, plan.getAssetsType() == 1 ? "本地" : "发布", plan.getName()));
            notice.setRead(0);
            notice.setMsgType(NoticeConstant.MSG_TYPE_DEVL_TMPLATE);
            notice.setUserName(plan.getCreatorCode());
            //跳转参数
            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> params = new ConcurrentHashMap<>();
            params.put(NoticeConstant.SOURCE_TYPE, plan.getAssetsType() - 1);
            params.put(NoticeConstant.PLAN_ID, plan.getId());

            keywords.add(new EamNoticeKeyword(plan.getName(), params));
            notice.setKeywords(keywords);
            notice.setTag(NoticeConstant.TAG_PLAN);
            notice.setCustomer(plan.getId().toString());
            notice.setCustomer1(params.get(NoticeConstant.SOURCE_TYPE).toString());
            //维护方案创建者code用以区分协作者
            notice.setCustomer2(plan.getCreatorCode());
            notice.setIsDeleted(0);
            notices.add(notice);
        }
        eamNoticeDao.saveOrUpdateBatch(notices);
    }

    @Override
    public void deliverableTemplataMsgSyncShare(DeliTemplateMsgSaveVo saveVo) {
        if (saveVo == null || saveVo.getMsgId() == null) {
            LOGGER.info("消息，缺失参数 结束");
            return;
        }
        EamNotice notice = eamNoticeDao.getById(saveVo.getMsgId());
        if (notice == null) {
            LOGGER.info("消息，未找到消息内容，结束：{}", saveVo.getMsgId());
            return;
        }
        if (!notice.getMsgType().equals(NoticeConstant.MSG_TYPE_DEVL_TMPLATE)) {
            LOGGER.info("消息，不支持同步协作者的消息类型：{}", notice.getMsgType());
            return;
        }
        if (notice.getCustomer1().equals("1")) {
            LOGGER.info("消息，不支持同步协作者的资产类别：{}", notice.getCustomer1());
            return;
        }
        String currentUserLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        if (!notice.getCustomer2().equals(currentUserLoginCode)) {
            LOGGER.info("消息，非方案owner，无同步消息协作者权限：owner:{},currentUserLoginCode:{}", notice.getCustomer2(), currentUserLoginCode);
            return;
        }
        //获取方案协作者
        List<PlanDesignShareRecordDTO> planDesignShareRecordDTOS = planDesignInstanceService.findShareRecordList(Long.valueOf(notice.getCustomer()));
        if (CollectionUtils.isEmpty(planDesignShareRecordDTOS)) {
            LOGGER.info("消息，当前方案暂无协作者，结束：{}", notice.getCustomer());
            return;
        }
        List<String> loginCodes = planDesignShareRecordDTOS.stream().map(PlanDesignShareRecordDTO::getSharedLoginCode).distinct().collect(Collectors.toList());
        for (String loginCode : loginCodes) {
            notice.setId(ESUtil.getUUID());
            notice.setUserName(loginCode);
            notice.setCreateTime(ESUtil.getNumberDateTime());
            notice.setRead(0);
            eamNoticeDao.saveOrUpdate(notice);
        }
    }

    @Override
    public void batchSaveNotice(List<EamNotice> noticeList) {
        if (CollectionUtils.isEmpty(noticeList)) {
            return;
        }
        eamNoticeDao.saveOrUpdateBatch(noticeList);
    }

    @Override
    public void sharePublishAssertMsgSave(SharePublishAssertMsgVo saveVo) {
        if (saveVo == null
                || StringUtils.isBlank(saveVo.getAssertOwnerCode())
                || StringUtils.isBlank(saveVo.getType())
                || StringUtils.isBlank(saveVo.getAssertName())
                || StringUtils.isBlank(saveVo.getAssertId())
                || saveVo.getShareUserId() == null
                || StringUtils.isBlank(saveVo.getShareUserName())) {
            LOGGER.info("消息，缺失参数 结束");
            return;
        }
        if (!NoticeConstant.TAG_DIAGRAM.equals(saveVo.getType())
                && !NoticeConstant.TAG_PLAN.equals(saveVo.getType())) {
            LOGGER.info("消息，不支持的资产发布类型 结束");
            return;
        }
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
        notice.setContent(String.format(NoticeConstant.SHARE_PUBLISH_ASSERT,
                NoticeConstant.TAG_DIAGRAM.equals(saveVo.getType()) ?
                        "视图" : "方案", saveVo.getAssertName(), saveVo.getShareUserName()));
        notice.setRead(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_SHARE_PUBLISH_ASSERT);
        notice.setUserName(saveVo.getAssertOwnerCode());
        //跳转参数
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.SOURCE_TYPE, 0);
        params.put(NoticeConstant.TAG_DIAGRAM.equals(saveVo.getType()) ? NoticeConstant.DIAGRAM_ID : NoticeConstant.PLAN_ID, saveVo.getAssertId());

        keywords.add(new EamNoticeKeyword(saveVo.getAssertName(), params));
        notice.setKeywords(keywords);
        notice.setTag(saveVo.getType());
        notice.setCustomer(saveVo.getShareUserId().toString());
        notice.setCustomer1(saveVo.getAssertId());
        notice.setCustomer2(saveVo.getAssertName());
        notice.setCustomer3(saveVo.getShareUserName());
        notice.setIsDeleted(0);
        eamNoticeDao.saveOrUpdate(notice);
    }

    @Override
    public void archReviewCirCulateMsgSave(List<ArchReviewCirCulateMsgVo> msgVos) {
        if (CollectionUtils.isEmpty(msgVos)) {
            LOGGER.info("消息，缺失参数 结束");
            return;
        }
        List<EamNotice> notices = new ArrayList<>();
        for (ArchReviewCirCulateMsgVo msgVo : msgVos) {
            if (msgVo == null
                    || StringUtils.isBlank(msgVo.getCreatorName())
                    || StringUtils.isBlank(msgVo.getCirCulator())
                    || StringUtils.isBlank(msgVo.getItemName())
                    || msgVo.getArchReviewId() == null
                    || msgVo.getCreatorId() == null) {
                LOGGER.info("消息，缺失参数 跳过");
                continue;
            }
            EamNotice notice = new EamNotice();
            notice.setId(ESUtil.getUUID());
            notice.setDomainId(DEFAULT_DOMAIN_ID);
            notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
            notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
            notice.setContent(String.format(NoticeConstant.ARCH_REVIEW_CIRCULATE_TEMPLATE, msgVo.getCreatorName(), msgVo.getItemName()));
            notice.setRead(0);
            notice.setMsgType(NoticeConstant.MSG_TYPE_ARCH_REVIEW_CIRCULATE);
            notice.setUserName(msgVo.getCirCulator());
            //跳转参数
            List<EamNoticeKeyword> keywords = new ArrayList<>();
            Map<String, Object> params = new ConcurrentHashMap<>();
            params.put(NoticeConstant.SOURCE_TYPE, 0);
            params.put(NoticeConstant.ARCH_REVIEW_ID, msgVo.getArchReviewId());

            keywords.add(new EamNoticeKeyword(msgVo.getItemName(), params));
            notice.setKeywords(keywords);
            notice.setTag(NoticeConstant.TAG_ARCH_REVIEW);
            notice.setCustomer(msgVo.getCreatorId().toString());
            notice.setCustomer1(msgVo.getCreatorName());
            notice.setCustomer2(msgVo.getItemName());
            notice.setIsDeleted(0);
            notices.add(notice);
        }
        if (!CollectionUtils.isEmpty(notices)) {
            eamNoticeDao.saveOrUpdateBatch(notices);
        }
    }

    @Override
    public void planPublishFail(PlanDesignInstance instance) {
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_WORKFLOW);
        notice.setRead(0);
        notice.setUserName(instance.getCreatorCode());
        notice.setTag(NoticeConstant.TAG_PLAN);
        notice.setIsDeleted(0);
        notice.setMsgType(NoticeConstant.MSG_TYPE_PLAN_PUBLISH_FAIL);
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        notice.setContent(String.format(NoticeConstant.PLAN_PUBLISH_FAIL, instance.getName()));
        params.put(NoticeConstant.PLAN_ID, instance.getId().toString());
        params.put(NoticeConstant.SOURCE_TYPE, 0);
        notice.setCustomer(instance.getName());
        notice.setCustomer1(params.get(NoticeConstant.PLAN_ID).toString());
        keywords.add(new EamNoticeKeyword(instance.getName(), params));
        notice.setKeywords(keywords);
        eamNoticeDao.saveOrUpdate(notice);
    }

    @Override
    public void questionMsgSave(QuestionMsgDTO questionMsgDTO) {
        if (questionMsgDTO == null) {
            LOGGER.info("消息，questionMsgDTO 为空 结束");
            return;
        }
        if (StringUtils.isEmpty(questionMsgDTO.getType())) {
            LOGGER.info("消息，type 为空 结束");
            return;
        }
        if (StringUtils.isEmpty(questionMsgDTO.getPlanName())) {
            LOGGER.info("消息，planName 为空 结束");
            return;
        }
        if (StringUtils.isEmpty(questionMsgDTO.getCurrentUserName())) {
            LOGGER.info("消息，currentUserName 为空 结束");
            return;
        }

        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
        notice.setRead(0);
        notice.setTag(NoticeConstant.TAG_PLAN);
        notice.setIsDeleted(0);
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        keywords.add(new EamNoticeKeyword("", params));
        notice.setKeywords(keywords);

        switch (questionMsgDTO.getType()) {
            case "create":
                if (StringUtils.isEmpty(questionMsgDTO.getSubmitter())) {
                    LOGGER.info("消息，submitter 为空 结束");
                    return;
                }
                notice.setMsgType(NoticeConstant.MSG_TYPE_QUESTION_CREATE);
                notice.setUserName(questionMsgDTO.getSubmitter());
                notice.setContent(String.format(NoticeConstant.QUESTION_CREATE, questionMsgDTO.getCurrentUserName(), questionMsgDTO.getPlanName()));
                break;
            case "correction":
                if (StringUtils.isEmpty(questionMsgDTO.getQuestionCreateUser())) {
                    LOGGER.info("消息，questionCreateUser 为空 结束");
                    return;
                }
                notice.setMsgType(NoticeConstant.MSG_TYPE_QUESTION_CORRECTION);
                notice.setUserName(questionMsgDTO.getQuestionCreateUser());
                notice.setContent(String.format(NoticeConstant.QUESTION_CORRECTION, questionMsgDTO.getPlanName(), questionMsgDTO.getCurrentUserName()));
                break;
            case "pass":
                if (StringUtils.isEmpty(questionMsgDTO.getQuestionCorrectionUser())) {
                    LOGGER.info("消息，questionCorrectionUser 为空 结束");
                    return;
                }
                notice.setMsgType(NoticeConstant.MSG_TYPE_QUESTION_VERIFY_PASS);
                notice.setUserName(questionMsgDTO.getQuestionCorrectionUser());
                notice.setContent(String.format(NoticeConstant.QUESTION_VERIFY_PASS, questionMsgDTO.getPlanName(), questionMsgDTO.getCurrentUserName()));
                break;
            case "noPass":
                if (StringUtils.isEmpty(questionMsgDTO.getQuestionCorrectionUser())) {
                    LOGGER.info("消息，questionCorrectionUser 为空 结束");
                    return;
                }
                notice.setMsgType(NoticeConstant.MSG_TYPE_QUESTION_VERIFY_NO_PASS);
                notice.setUserName(questionMsgDTO.getQuestionCorrectionUser());
                notice.setContent(String.format(NoticeConstant.QUESTION_VERIFY_NO_PASS, questionMsgDTO.getPlanName()));
                break;
            default:
                LOGGER.info("消息，不支持的问题处理类型 结束");
                return;
        }
        sendGTJob(notice, notice.getId().toString(), "", "");
        eamNoticeDao.saveOrUpdate(notice);
    }

    /**
     * 发送国投门户待阅
     * @param notice
     */
    private void sendGTJob(EamNotice notice, String notifyId, String link, String mobileLink) {
        if (gtDataImitate) {
            return;
        }
        GTSendPendingJobInfo sendPendingJobInfo = new GTSendPendingJobInfo();
        sendPendingJobInfo.setNotifyId(notifyId);
        sendPendingJobInfo.setSubject(notice.getContent());
        sendPendingJobInfo.setLink(link);
        sendPendingJobInfo.setMobileLink(mobileLink);
        sendPendingJobInfo.setTargets(Arrays.asList(notice.getUserName()));
        sendPendingJobInfo.setCreator(SysUtil.getCurrentUserInfo().getLoginCode());
        sendPendingJobInfo.setTodoType(2);
        sendPendingJobInfo.setTodoLevel(3);
        boolean success;
        try {
            LOGGER.info("推送门户待办:{}", JSON.toJSONString(sendPendingJobInfo));
            success = gtJobSvc.sendPendingJob(sendPendingJobInfo);
            LOGGER.info("推送门户待办结果:{}", success);
        } catch (Exception e) {
            LOGGER.info("推送门户待办失败:{}", JSON.toJSONString(e));
            success = false;
        }
        if (!success) {
            LOGGER.error("推送门户待办失败");
        } else {
            // customer 存储门户待阅id 用于后续关联
            notice.setCustomer(sendPendingJobInfo.getNotifyId());
        }
    }

    @Override
    public void annotationMsgSave(AnnotationMsgDTO annotationMsgDTO) {
        if (annotationMsgDTO == null
                || StringUtils.isBlank(annotationMsgDTO.getType())
                || StringUtils.isBlank(annotationMsgDTO.getOperator())
                || StringUtils.isBlank(annotationMsgDTO.getOwner())
                || StringUtils.isBlank(annotationMsgDTO.getArchReviewName())
                || annotationMsgDTO.getArchReviewId() == null
                || StringUtils.isBlank(annotationMsgDTO.getProcessInstanceId())) {
            LOGGER.info("消息，缺失参数 结束");
            return;
        }
        EamNotice notice = new EamNotice();
        notice.setId(ESUtil.getUUID());
        notice.setDomainId(DEFAULT_DOMAIN_ID);
        notice.setType(NoticeConstant.NOTICE_TYPE_MSG);
        notice.setClassify(NoticeConstant.NOTICE_CLASSIFY_SYSTEM);
        notice.setRead(0);
        notice.setTag(NoticeConstant.TAG_ARCH_REVIEW);
        notice.setIsDeleted(0);
        //跳转参数
        List<EamNoticeKeyword> keywords = new ArrayList<>();
        Map<String, Object> params = new ConcurrentHashMap<>();
        params.put(NoticeConstant.SOURCE_TYPE, 0);
        params.put(NoticeConstant.ARCH_REVIEW_ID, annotationMsgDTO.getArchReviewId());
        params.put(NoticeConstant.ARCH_REVIEW_PROCESS_INSTANCE_ID, annotationMsgDTO.getProcessInstanceId());
        keywords.add(new EamNoticeKeyword(annotationMsgDTO.getArchReviewName(), params));
        notice.setKeywords(keywords);
        notice.setMsgType(NoticeConstant.MSG_TYPE_ANNOTATION);
        notice.setUserName(annotationMsgDTO.getOwner());

        switch (annotationMsgDTO.getType()) {
            case "create":
                notice.setContent(String.format(NoticeConstant.ANNOTATION_CREATE, annotationMsgDTO.getOperator(), annotationMsgDTO.getArchReviewName()));
                break;
            case "reply_from_other":
                notice.setContent(String.format(NoticeConstant.ANNOTATION__REPLY_FROM_OTHER, annotationMsgDTO.getArchReviewName(), annotationMsgDTO.getOperator()));
                break;
            case "reply_from_creator":
                notice.setContent(String.format(NoticeConstant.ANNOTATION_REPLY_FROM_CREATOR, annotationMsgDTO.getOperator(), annotationMsgDTO.getArchReviewName()));
                break;
            default:
                LOGGER.info("消息，不支持的问题处理类型 结束");
                return;
        }
        eamNoticeDao.saveOrUpdate(notice);
        String notifyId = notice.getId().toString();
        String baseUrl = httpPath.replace("/tarsier-eam", "").replace("/rsm", "");
        String pcLink = baseUrl.concat("/approval-page#/ArchSchemeApproveDetail")
                .concat("/").concat(annotationMsgDTO.getArchReviewId().toString())
                .concat("?circulateId=").concat(notifyId);
        String mobileLink = baseUrl.concat("/approval-mobile#/ArchSchemeApproveToPC")
                .concat("/").concat(annotationMsgDTO.getArchReviewId().toString())
                .concat("?circulateId=").concat(notifyId);
        sendGTJob(notice, notifyId, pcLink, mobileLink);
    }
}
